using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Beetle.Clients;

public class AsynNode<T> where T : Package
{
	private Action<IChannel> m_a;

	private EventPacketRecievMessage m_b;

	private EventChannelError c;

	private bool d;

	private Timer e;

	private int f;

	private List<IChannel> g = new List<IChannel>();

	private Exception h;

	private bool i;

	[CompilerGenerated]
	private string j;

	[CompilerGenerated]
	private int k;

	[CompilerGenerated]
	private int l;

	[CompilerGenerated]
	private string m;

	[CompilerGenerated]
	private string[] n;

	[CompilerGenerated]
	private int o;

	[CompilerGenerated]
	private string p;

	public string Host
	{
		[CompilerGenerated]
		get
		{
			return j;
		}
		[CompilerGenerated]
		private set
		{
			j = value;
		}
	}

	public int Port
	{
		[CompilerGenerated]
		get
		{
			return k;
		}
		[CompilerGenerated]
		private set
		{
			k = value;
		}
	}

	public int MaxConnections
	{
		[CompilerGenerated]
		get
		{
			return l;
		}
		[CompilerGenerated]
		set
		{
			l = value;
		}
	}

	public string GroupName
	{
		[CompilerGenerated]
		get
		{
			return m;
		}
		[CompilerGenerated]
		set
		{
			m = value;
		}
	}

	public string[] GroupNodes
	{
		[CompilerGenerated]
		get
		{
			return n;
		}
		[CompilerGenerated]
		set
		{
			n = value;
		}
	}

	public int DetectTime
	{
		[CompilerGenerated]
		get
		{
			return o;
		}
		[CompilerGenerated]
		set
		{
			o = value;
		}
	}

	public string Name
	{
		[CompilerGenerated]
		get
		{
			return p;
		}
		[CompilerGenerated]
		set
		{
			p = value;
		}
	}

	public Exception LastError => h;

	public IList<IChannel> Channels => g;

	public bool Available => i;

	public AsynNode(string host, int port, int maxconnections, EventPacketRecievMessage receive, EventChannelError error, Action<IChannel> channelCreated)
	{
		DetectTime = 10;
		Host = host;
		Port = port;
		MaxConnections = maxconnections;
		i = false;
		this.b = receive;
		c = error;
		this.a = channelCreated;
	}

	private void a(object A_0, ChannelDisposedEventArgs A_1)
	{
		a(A_1.Channel);
		a(A_0: false);
	}

	private void b(IChannel A_0)
	{
		lock (this)
		{
			b(A_0);
		}
	}

	private void a(IChannel A_0)
	{
		lock (this)
		{
			g.Remove(A_0);
		}
	}

	public void Connect()
	{
		if (e == null)
		{
			e = new Timer(a, null, -1, DetectTime * 1000);
		}
		ThreadPool.QueueUserWorkItem(a);
	}

	private void a(object A_0)
	{
		if (e != null)
		{
			e.Change(-1, DetectTime * 1000);
		}
		try
		{
			do
			{
				IChannel channel = b();
				if (this.a != null)
				{
					this.a(channel);
				}
				g.Add(channel);
			}
			while (g.Count < MaxConnections);
			d = false;
			a(A_0: true);
		}
		catch (Exception a_)
		{
			d = false;
			a(a_);
			a(A_0: false);
		}
	}

	private IChannel b()
	{
		IChannel channel = TcpServer.CreateClient<T>(Host, Port, this.b);
		channel.ChannelError += c;
		channel.ChannelDisposed += a;
		TcpServer.SetKeepAliveValues(channel.Socket, 5000u, 5000u);
		channel.BeginReceive();
		return channel;
	}

	internal void a(Exception A_0)
	{
		h = A_0;
	}

	private IChannel a()
	{
		lock (this)
		{
			if (!Available || g.Count == 0)
			{
				return null;
			}
			f++;
			if (f >= g.Count)
			{
				f = 0;
			}
			return g[f];
		}
	}

	public bool Send(object msg)
	{
		if (g.Count == 0)
		{
			return false;
		}
		return a()?.Send(msg) ?? false;
	}

	private void a(bool A_0)
	{
		lock (this)
		{
			i = A_0;
			if (i)
			{
				return;
			}
			foreach (IChannel item in g)
			{
				item.Dispose();
			}
			g.Clear();
			if (!d)
			{
				d = true;
				if (e != null)
				{
					e.Change(DetectTime * 1000, DetectTime * 1000);
				}
			}
		}
	}
}
